package geometria;

import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import modelo.TiempoInvalidoException;
import modelo.Velocidad;

/**
 * 
 * Esta clase representa un par ordenado en el plano.
 * 
 */
public class Coordenada implements Comparable<Coordenada> {

	protected Point2D.Double p;

	public Coordenada(Double x, Double y) {
		this.p = new Point2D.Double(x, y);
	}

	public Coordenada() {
		this.p = new Point2D.Double();
	}

	public double getX() {
		return this.p.x;
	}

	public double getY() {
		return this.p.y;
	}

	public boolean coincideCon(Coordenada otra, Double tolerancia) {

		double dist = this.p.distance(otra.p);
		return (dist <= tolerancia);

	}

	public Coordenada menos(Coordenada otra) {
		return new Coordenada(this.getX() - otra.getX(), this.getY()
				- otra.getY());
	}

	/**
	 * Permite obtener una coordenada que resulta de desplazar this con
	 * velocidad v durante el tiempo indicado.
	 */
	public Coordenada moverConVelocidad(Velocidad v, Double tiempo) {

		Double nuevax, nuevay;

		if (tiempo < 0)
			throw new TiempoInvalidoException();
		nuevax = this.p.x + (tiempo * v.getX());
		nuevay = this.p.y + (tiempo * v.getY());

		return new Coordenada(nuevax, nuevay);
	}

	public void normalizar() {

		Double moduloAnterior = this.getModulo();

		this.p.x = (this.p.x) / moduloAnterior;
		this.p.y = (this.p.y) / moduloAnterior;
	}

	public double getModulo() {

		// El módulo de un vector es su distancia al origen de coordenadas
		return this.p.distance(0D, 0D);
	}

	public Double getDistancia(Coordenada otra) {
		return this.p.distance(otra.p);
	}

	/**
	 * 
	 * @param destino
	 *            coordenada de destino
	 * @param tiempo
	 *            tiempo durante el cual me muevo
	 * @param velocidad
	 *            velocidad con la que me muevo
	 */

	public void mover(Coordenada destino, Double tiempo, Double velocidad) {

		Double dx, dy;

		Coordenada direccion;

		direccion = destino.menos(this);
		direccion.normalizar();
		direccion.MultiplicarPor(velocidad);

		dx = direccion.getX() * tiempo;
		dy = direccion.getY() * tiempo;
		Coordenada nuevaCoordenadaPotencial = new Coordenada(this.getX() + dx,
				this.getY() + dy);

		if (destino.estaEnElMedio(this, nuevaCoordenadaPotencial)) {
			// Nos pasamos!
			this.p = destino.p;
		} else {
			this.p = nuevaCoordenadaPotencial.p;
		}
	}

	public boolean estaEnElMedio(Coordenada c1, Coordenada c2) {
		Line2D.Double laux = new Line2D.Double(c1.p, c2.p);
		Rectangle2D.Double raux = new Rectangle2D.Double(this.getX(),
				this.getY(), 1D, 1D);
		return raux.intersectsLine(laux);
	}

	@Override
	public String toString() {
		return this.p.toString();
	}

	@Override
	public boolean equals(Object otra) {
		return this.coincideCon((Coordenada) otra, 1D);
	}

	@Override
	public int compareTo(Coordenada otra) {
		if (this.coincideCon(otra, 1D))
			return 0;
		return 1;
	}

	private void MultiplicarPor(Double velocidad) {
		this.p = new Point2D.Double(velocidad * this.getX(), velocidad
				* this.getY());
	}

	public int getCuadrante() {
		if (p.x > 0 && p.y > 0)
			return 0;
		else if (p.x < 0 && p.y > 0)
			return 1;
		else if (p.x < 0 && p.y < 0)
			return 2;
		else if (p.x >= 0 && p.y <= 0)
			return 3;
		return -1;
	}

}
